# -*- coding: utf-8 -*-

"""
@author: bw
@contact: bw@handsdriver.net
"""

__all__ = ('getUtility',)

import funcy    as F
import operator as O

from eof.util import imports

from . import shortcuts as ztk

reactor = imports.lazyModule('eof.txbr.reactor')  # @xxx: (!) not implemented yet


MAX_BLOCKING_SECONDS = 2 * 60


def getUtility(provided, name='', context=None, blocking=None):
	assert 0, 'thread block'

	if type(blocking) not in (int, long, float) and blocking not in (None, True, False):
		raise TypeError('blocking must be <None>, <True>, <int> or <float>', type(blocking))

	utility = ztk.queryUtility(provided, name, context)

	if utility is None:
		if blocking in (None, False) or blocking <= 0:
			raise ztk.ComponentLookupError(provided, name)

		stoptime = reactor.seconds() + (MAX_BLOCKING_SECONDS if blocking is True else blocking)

		while True:
			try:
				timeout = stoptime - reactor.seconds()
				if timeout <= 0:
					raise LookupError
				utility, event = waitEvent((provided, ztk.IRegistered), context, timeout)
			except LookupError:
				raise ztk.ComponentLookupError(provided, name)

			if event.object.name == name:
				break

	return utility


def waitEvent(required, context=None, timeout=None):
	assert 0, 'thread block'

	loop  = None
	queue = reactor.Queue()

	def handler(*args):
		loop = reactor.Loop()
		queue.put((loop,) + args)

	sm = ztk.getSiteManager(context)
	sm_roots = set(F.tree_leaves(sm, follow=O.attrgetter('__bases__'), children=O.attrgetter('__bases__')))

	# @todo: handle tree of SM

	F.invoke(sm_roots, 'registerHandler', handler, required)
	try:
		result = queue.get(timeout=timeout)
		loop, result = result[0], result[1:]
	except reactor.QueueTimeout:
		raise LookupError('timeout')
	finally:
		F.invoke(sm_roots, 'unregisterHandler', handler, required)
		if loop is not None and not loop.blocking:  # @xxx: blocking -- перестраховка, его не должно быть никогда
			loop.wake()

	return result
